<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        body {
            margin: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-color: #f0f0f0;
            font-family: Arial, sans-serif;
        }
        canvas {
            border: 1px solid black;
        }
        .controls {
            position: absolute;
            top: 10px;
            left: 10px;
            z-index: 10;
            background: rgba(255, 255, 255, 0.8);
            padding: 10px;
            border-radius: 5px;
        }
        .controls label {
            display: block;
            margin-bottom: 5px;
        }
    </style>
</head>
<body>
    <div class="controls">
        <label for="gravity">重力: <span id="gravityValue">0.1</span></label>
        <input type="range" id="gravity" min="0" max="1" step="0.1" value="0.1">

        <label for="friction">摩擦力: <span id="frictionValue">0.005</span></label>
        <input type="range" id="friction" min="0" max="0.05" step="0.001" value="0.005">
    </div>
    <canvas id="physicsCanvas"></canvas>
    
    <script>
        //由AI创建的小页面

        let gravity = 0.1;
        let friction = 0.005;
        
        const canvas = document.getElementById('physicsCanvas');
        const ctx = canvas.getContext('2d');
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        class RigidBody {
            constructor(x, y, radius) {
                this.x = x;
                this.y = y;
                this.radius = radius;
                this.mass = radius * radius;
                this.velocity = { x: 0, y: 0 };
                this.dragging = false;
                this.offset = { x: 0, y: 0 };
            }

            draw() {
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
                ctx.fillStyle = this.dragging ? 'red' : 'blue';
                ctx.fill();
                ctx.closePath();
            }

            update() {
                if (!this.dragging) {
                    this.velocity.y += gravity;
                    this.x += this.velocity.x;
                    this.y += this.velocity.y;
                    
                    this.velocity.x *= (1-friction);
                    this.velocity.y *= (1-friction);

                    if(Math.abs(this.velocity.x)<0.01)
                    {
                        this.velocity.x = 0;
                    }
                    if(Math.abs(this.velocity.y)<0.01)
                    {
                        this.velocity.y = 0;
                    }
                    
                    // 检测边界碰撞

                    if (this.x - this.radius < 0 || this.x + this.radius > canvas.width) {
                        if(this.x - this.radius < 0)
                        {
                            this.x = 0+this.radius;
                        }
                        else
                        {
                            this.x = canvas.width-this.radius;
                        }
                        this.velocity.x *= -1;
                    }
                    if (this.y - this.radius < 0 || this.y + this.radius > canvas.height) {
                        if(this.y - this.radius < 0)
                        {
                            this.y = 0+this.radius;
                        }
                        else
                        {
                            this.y = canvas.height-this.radius;
                        }
                        this.velocity.y *= -1;
                    }
                }
            }

            isPointInside(px, py) {
                return Math.sqrt((px - this.x) ** 2 + (py - this.y) ** 2) <= this.radius;
            }
        }

        const bodies = [];
        let selectedBody = null;
        // 初始化鼠标位置和速度相关的变量
        let lastMousePosition = { x: 0, y: 0 }; // 上一次鼠标的位置，初始化为坐标原点
        const mouseVelCount=5; // 鼠标速度的计算基于最近5次鼠标位置的变动
        let mouseVel=[]; // 存储鼠标速度的数组
        // 初始化鼠标速度数组，所有速度初始值设为0
        for(let i=0;i<=mouseVelCount-1;i++)
        {
            mouseVel.push({x:0,y:0});
        }

        function createRigidBody(x, y, radius) {
            bodies.push(new RigidBody(x, y, radius));
        }

        function detectCollisions() {
            for (let i = 0; i < bodies.length; i++) {
                for (let j = i + 1; j < bodies.length; j++) {
                    const dx = bodies[j].x - bodies[i].x;
                    const dy = bodies[j].y - bodies[i].y;
                    const distance = Math.sqrt(dx * dx + dy * dy);

                    if (distance < bodies[i].radius + bodies[j].radius) {
                        const nx = dx / distance;
                        const ny = dy / distance;
                        const p = 2 * ((bodies[i].velocity.x * nx + bodies[i].velocity.y * ny) -
                                      (bodies[j].velocity.x * nx + bodies[j].velocity.y * ny)) /
                                  (bodies[i].mass + bodies[j].mass);

                        const impulseX = p * nx;
                        const impulseY = p * ny;

                        if (!bodies[i].dragging)
                        {
                            bodies[i].velocity.x -= impulseX * bodies[j].mass;
                            bodies[i].velocity.y -= impulseY * bodies[j].mass;
                            
                            bodies[i].x = bodies[j].x - (bodies[i].radius + bodies[j].radius)*dx/distance;
                            bodies[i].y = bodies[j].y - (bodies[i].radius + bodies[j].radius)*dy/distance;
                        }
                        if(!bodies[j].dragging)
                        {
                            bodies[j].velocity.x += impulseX * bodies[i].mass;
                            bodies[j].velocity.y += impulseY * bodies[i].mass;
                            
                            bodies[j].x = bodies[i].x + (bodies[i].radius + bodies[j].radius)*dx/distance;
                            bodies[j].y = bodies[i].y + (bodies[i].radius + bodies[j].radius)*dy/distance;
                        }

                    }
                }
            }
        }

        function animate() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            for (const body of bodies) {
                body.update();
                body.draw();
            }
            detectCollisions();
            requestAnimationFrame(animate);
        }

        canvas.addEventListener('mousedown', (e) => {
            const mouseX = e.clientX;
            const mouseY = e.clientY;

            for (const body of bodies) {
                if (body.isPointInside(mouseX, mouseY)) {
                    selectedBody = body;
                    selectedBody.dragging = true;
                    selectedBody.offset.x = mouseX - body.x;
                    selectedBody.offset.y = mouseY - body.y;

                    for(let i=0;i<=mouseVelCount-1;i++)
                    {
                        mouseVel[i].x=0;
                        mouseVel[i].y=0;
                    }
                    break;
                }
            }
        });

        canvas.addEventListener('mousemove', (e) => {
            if (selectedBody && selectedBody.dragging) {
                selectedBody.x = e.clientX - selectedBody.offset.x;
                selectedBody.y = e.clientY - selectedBody.offset.y;
            }

            for(let i=0;i<=mouseVelCount-2;i++)
            {
                mouseVel[i+1] = mouseVel[i];
            }
            mouseVel[0].x = e.clientX - lastMousePosition.x;
            mouseVel[0].y = e.clientY - lastMousePosition.y;
            lastMousePosition.x = e.clientX;
            lastMousePosition.y = e.clientY;
        });

        canvas.addEventListener('mouseup', () => {
            if (selectedBody) {
                selectedBody.dragging = false;

                let averageMouseVel = {x:0,y:0};
                for(let i=0;i<=mouseVelCount-1;i++)
                {
                    averageMouseVel.x += mouseVel[i].x;
                    averageMouseVel.y += mouseVel[i].y;
                }
                averageMouseVel.x /= mouseVelCount;
                averageMouseVel.y /= mouseVelCount;

                const dragCoeff=0.25;// 速度调整系数
                selectedBody.velocity.x = averageMouseVel.x * dragCoeff; 
                selectedBody.velocity.y = averageMouseVel.y * dragCoeff; 
            }
            selectedBody = null;
        });

        // 监听窗口大小变化并重新设置画布大小
        window.addEventListener('resize',() =>
        {  
            if(window.innerWidth > 500 && window.innerHeight> 500)
            {
                canvas.width = window.innerWidth;
                canvas.height = window.innerHeight;
            }
        }
        )
        
       document.getElementById('gravity').addEventListener('input', (e) => {
            gravity = parseFloat(e.target.value);
            document.getElementById('gravityValue').textContent = gravity.toFixed(2);
        });

        document.getElementById('friction').addEventListener('input', (e) => {
            friction = parseFloat(e.target.value);
            document.getElementById('frictionValue').textContent = friction.toFixed(3);
        });
        
        // 创建一些初始刚体
        createRigidBody(100, 100, 30);
        createRigidBody(200, 200, 40);
        createRigidBody(300, 300, 50);

        animate();
    </script>
</body>
</html>
